package loghoop

import (
	"bytes"
	"fmt"
	"gitee.com/lizhi353/fxunion/requestctx"
	"github.com/gin-gonic/gin"
	rotatelogs "github.com/lestrrat-go/file-rotatelogs"
	"github.com/rifflock/lfshook"
	"github.com/sirupsen/logrus"
	"io"
	"os"
	"strings"
	"time"
)

type MyFormatter struct {
	TimestampFormat string   // default: time.StampMilli = "Jan _2 15:04:05.000"
}

var Entry = &logrus.Entry{}
var LogAppName string


//启动
func SetUp(appname string)  {
	LogAppName = appname
	logrus.SetOutput(os.Stdout)
	logrus.SetReportCaller(true)
	logrus.SetLevel(logrus.TraceLevel)

	logrus.AddHook(logFsHook())
	logrus.SetFormatter(&MyFormatter{})

}

func AccessLog() gin.HandlerFunc {
	return func(ctx *gin.Context) {
		method := ctx.Request.Method
		url := ctx.Request.URL.Path
		urlPath := method + ":"+ url
		defaultParams := requestctx.Instance(ctx).GetDefaultParams()
		defaultParams["requestPath"] = urlPath
		defaultParams["type"] = "API"
		Entry = logrus.WithFields(defaultParams)
		ctx.Next()
	}
}


//注册文件分器割
func logFsHook() logrus.Hook {
	logPath := "/data/log/"
	if len(os.Args) == 1 || ( len(os.Args) > 1 && (os.Args[1] == "dev" || os.Args[1] == "onlinelocal" ) ) {
		logPath = "./logs/"
	}
	//注册请求日志存储路径
	infoWriter, err := rotatelogs.New(
		logPath + LogAppName+".log.%Y%m%d",
		rotatelogs.WithLinkName(logPath+LogAppName+".log"),
		rotatelogs.WithRotationTime(time.Hour*24),
		rotatelogs.WithRotationSize(1024*1024*500),
	)

	if err != nil {
		logrus.Errorf("config local file system for loggers error: %v", err)
	}

	w := io.MultiWriter(os.Stdout, infoWriter)
	gin.DefaultWriter = w

	lfsHook := lfshook.NewHook(lfshook.WriterMap{
		logrus.TraceLevel: infoWriter,
		logrus.DebugLevel: infoWriter,
		logrus.InfoLevel:  infoWriter,
		logrus.WarnLevel:  infoWriter,
		logrus.ErrorLevel: infoWriter,
		logrus.FatalLevel: infoWriter,
		logrus.PanicLevel: infoWriter,
	}, &MyFormatter{})
	return lfsHook
}


/**
  formart: [时间] [级别] [type] [线程] [类方法] [行数] [请求方法和路径] [终端编号] 自定义消息
  type: 系统日志还是访问日志，这里分别用api和system表示
*/
func (m *MyFormatter) Format(entry *logrus.Entry) ([]byte, error) {
	var b *bytes.Buffer
	if entry.Buffer != nil {
		b = entry.Buffer
	} else {
		b = &bytes.Buffer{}
	}

	timestamp := entry.Time.Format("2006-01-02 15:04:05,000")
	mtype := "SYSTEM"
	if _,ok := entry.Data["type"]; ok {
		mtype = entry.Data["type"].(string)
	}
	requestID := ""
	if _,ok := entry.Data["requestID"]; ok {
		requestID = entry.Data["requestID"].(string)
	}

	requestPath := ""
	if _,ok := entry.Data["requestPath"]; ok {
		requestPath = entry.Data["requestPath"].(string)
	}

	callFile, callLine, callFunc := getCallerInfo(entry)
	if len(callFunc) > 0 {
		callFunc = strings.Replace(callFunc, "gitee.com/lizhi353/fxunion/","", 1)
	}
	//formart: 时间|[级别]|[自定义标记]|[线程]|[类.函数]|[行数]|[请求方法 请求路径]|[终端请求编号]|自定义消息
	level := strings.ToUpper(fmt.Sprintf("%s", entry.Level))
	newLog := fmt.Sprintf("%s|[%s]|[%s]|[]|[%s]|[%d]|[%s]|[%s]|%s ", timestamp, level, mtype,
		callFile+":"+callFunc, callLine, requestPath, requestID, entry.Message)
	if value,ok := entry.Data["status"]; ok && value != "" {
		newLog += fmt.Sprintf(" -status: %v", entry.Data["status"].(int))
	}
	if value,ok := entry.Data["remoteAddr"]; ok && value != "" {
		newLog += fmt.Sprintf(" -remoteAddr: %v", entry.Data["remoteAddr"].(string))
	}
	if value,ok := entry.Data["params"]; ok && value != "" {
		newLog += fmt.Sprintf(" -params: %v", entry.Data["params"].(string))
	}
	if value,ok := entry.Data["userAgent"]; ok && value != "" {
		newLog += fmt.Sprintf(" -userAgent: %v", entry.Data["userAgent"].(string))
	}
	b.WriteString(newLog + "\n")
	return b.Bytes(), nil
}

/**
** @return
** @param file string 文件
** @param line int 行数
** @param func string 方法
 */
func getCallerInfo(entry *logrus.Entry) (string, int, string)  {
	filesArr := strings.Split(entry.Caller.File, "/")
	file := filesArr[len(filesArr)-1]
	line := entry.Caller.Line
	funcName := entry.Caller.Function
	funcName = strings.Replace(funcName, ".func1", "", 1)
	return file, line, funcName
}

// logrus info
func Info(args ...interface{})   {
	Entry.Log(logrus.InfoLevel, args...)
}

// logrus infof
func Infof(format string, args ...interface{}) {
	Entry.Logf(logrus.InfoLevel, format, args ...)
}

func Trace(args ...interface{}) {
	Entry.Log(logrus.TraceLevel, args...)
}

func Tracef(format string, args ...interface{}) {
	Entry.Logf(logrus.TraceLevel, format, args...)
}

// logrus debug
func Debug(args ...interface{}) {
	Entry.Log(logrus.DebugLevel, args...)
}

// logrus warn
func Warn(args ...interface{}) {
	Entry.Log(logrus.WarnLevel, args...)
}

// logrus error
func Error(args ...interface{}) {
	Entry.Log(logrus.ErrorLevel, args...)
}

// logrus errorf
func Errorf(format string, args ...interface{}) {
	Entry.Errorf(format, args ...)
}

func Fatal(args ...interface{}) {
	Entry.Fatal(args ...)
}

func Panic(args ...interface{}) {
	Entry.Panic(args ...)
}


func Infoln(args ...interface{}) {
	Entry.Logln(logrus.InfoLevel, args...)
}

func Println(args ...interface{}) {
	Entry.Infoln(args...)
}

func Warnln(args ...interface{}) {
	Entry.Logln(logrus.WarnLevel, args...)
}

func Warningln(args ...interface{}) {
	Entry.Warnln(args...)
}

func Errorln(args ...interface{}) {
	Entry.Logln(logrus.ErrorLevel, args...)
}

func Printf(format string, args ...interface{}) {
	Entry.Infof(format, args...)
}